package com.dashuai.modbus.config;

import com.dashuai.modbus.core.slave.ModbusTCPSlave;
import com.serotonin.modbus4j.exception.ModbusInitException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.util.List;

/**
 * <p>
 *
 * </p>
 *
 * @author QM
 * @date 2024/8/22
 */
@Slf4j
@EnableConfigurationProperties(TCPSlaveProperties.class)
@AutoConfigureOrder
public class TCPSlaveAutoConfiguration {


    @Autowired
    private TCPSlaveProperties tcpSlaveProperties;


    @Bean
    public ModbusTCPSlave modbusTCPSlave() throws ModbusInitException {

        final int port = tcpSlaveProperties.getPort();
        final boolean encapsulated = tcpSlaveProperties.getEncapsulated();
        final List<ProcessImageProperties> processImageList = tcpSlaveProperties.getProcessImages();

        checkTCPSlaveParameter(port, processImageList);

        final ModbusTCPSlave modbusTCPSlave = new ModbusTCPSlave(port, encapsulated, processImageList);
        new Thread(modbusTCPSlave, "modbus-tcp-slave").start();
        return modbusTCPSlave;
    }


    private void checkTCPSlaveParameter(int port, List<ProcessImageProperties> processImageList) throws ModbusInitException {

        if (port < 0 || port > 65535) {
            throw new ModbusInitException("The tcp port number is out of range");
        }

        if (processImageList != null && !processImageList.isEmpty()) {
            for (ProcessImageProperties processImageProperties : processImageList) {

                final List<CoilProperties> coilList = processImageProperties.getCoils();
                if (coilList != null && !coilList.isEmpty()) {
                    for (CoilProperties coilProperties : coilList) {
                        final int offset = coilProperties.getOffset();

                        if (offset < 1 || offset > 9999) {
                            throw new ModbusInitException("The address bit is out of range");
                        }
                    }
                }

                final List<InputProperties> inputList = processImageProperties.getInputs();
                if (inputList != null && !inputList.isEmpty()) {
                    for (InputProperties inputProperties : inputList) {
                        final int offset = inputProperties.getOffset();

                        if (offset < 1 || offset > 9999) {
                            throw new ModbusInitException("The address bit is out of range");
                        }
                    }
                }

                final RegisterProperties holdingRegister = processImageProperties.getHoldingRegister();
                if (holdingRegister != null) {
                    final int holdingOffset = holdingRegister.getStartOffset();
                    if (holdingOffset < 1 || holdingOffset > 9999) {
                        throw new ModbusInitException("The address bit is out of range");
                    }
                }


                final RegisterProperties inputRegister = processImageProperties.getInputRegister();
                if (inputRegister != null) {
                    final int inputOffset = inputRegister.getStartOffset();
                    if (inputOffset < 1 || inputOffset > 9999) {
                        throw new ModbusInitException("The address bit is out of range");
                    }
                }
            }
        } else {
            log.warn("The modbus tcp slave was created, but the address bits were not initialized");
        }

    }

}
